/**********************************************************************************************/
/* FBL_StringConversion.cpp                                                      			  */
/*                                                                       					  */
/* Copyright Paradigma, 1993-2006															  */
/* All Rights Reserved.                                                 					  */
/**********************************************************************************************/

#include <VShared/FBL/publ/Headers/StdAfx.h>

#include <VShared/FBL/publ/Util_classes/FBL_StringConversion.h>

#include <VShared/FBL/publ/Util_classes/FBL_String.h>


/**********************************************************************************************/
FBL_Begin_Namespace


/**********************************************************************************************/
// This converter is created by GetConverter_UTF8() singlenton,
// and lives up to the end of appication. 
//
namespace internal
{
	I_Converter* gConverterUTF8 = NULL;
}


/**********************************************************************************************/
I_Converter* GetConverter_UTF8( void )
{
	if( !internal::gConverterUTF8 )
		internal::gConverterUTF8 = CreateConverter( "UTF8" );
	
	return internal::gConverterUTF8;
}


#pragma mark -


/**********************************************************************************************/
StFromUTF16::StFromUTF16( 
	const String& 	inStr,
	const char* 	inEncoding )
:
	ConverterBase( inEncoding )
{
	Init();
	ConvertUsingInternalBuffer( inStr.c_str(), inStr.length() );
}


/**********************************************************************************************/
StFromUTF16::StFromUTF16( 
	const UChar* 	inUStr, 
	tslen 			inLen,
	const char* 	inEncoding )
:
	ConverterBase( inEncoding )
{
	Init();
	ConvertUsingInternalBuffer(inUStr, inLen);
}


/**********************************************************************************************/
StFromUTF16::StFromUTF16( 
	const UChar* 	inUStr, 
	const UChar* 	inEnd, 
	const char* 	inEncoding )
:
	ConverterBase( inEncoding )
{
	Init();
	ConvertUsingInternalBuffer( inUStr, tslen(inEnd - inUStr) );
}


#pragma mark -


/**********************************************************************************************/
StFromUTF16::StFromUTF16( 
	I_Converter* 	inConverter )
:
	ConverterBase( inConverter )
{
	Init();
}


/**********************************************************************************************/
StFromUTF16::StFromUTF16( 
	const String& 	inStr,
	I_Converter* 	inConverter )
:
	ConverterBase( inConverter )
{
	Init();
	ConvertUsingInternalBuffer( inStr.c_str(), inStr.length() );
}


/**********************************************************************************************/
StFromUTF16::StFromUTF16( 
	const UChar* 	inUStr, 
	tslen 			inLen,
	I_Converter* 	inConverter )
:
	ConverterBase( inConverter )
{
	Init();
	ConvertUsingInternalBuffer(inUStr, inLen);
}


/**********************************************************************************************/
StFromUTF16::StFromUTF16( 
	const UChar* 	inUStr, 
	const UChar* 	inEnd,
	I_Converter* 	inConverter )
:
	ConverterBase( inConverter )
{
	Init();
	ConvertUsingInternalBuffer( inUStr,  tslen(inEnd - inUStr) );
}


#pragma mark -


/**********************************************************************************************/
StFromUTF16::~StFromUTF16( void ) throw()
{
	Free();
}


/**********************************************************************************************/
void StFromUTF16::Init( void ) throw()
{
	mAStr = NULL;
	mLocal[ mLen = 0 ] = 0;
}


#pragma mark -


/**********************************************************************************************/
void StFromUTF16::Convert( const UChar* inUStr, tslen inLen )
{
	Free();

	if( !inUStr )
		return;

	ConvertUsingInternalBuffer(inUStr, inLen);
}


/**********************************************************************************************/
void StFromUTF16::Convert( const String& inStr )
{
	Convert(inStr.c_str(), inStr.length());
}


#pragma mark -


/**********************************************************************************************/
void StFromUTF16::ConvertUsingInternalBuffer( 
	const UChar* 	inUStr, 
	tslen 			inLen )
{
	if( !inUStr )
		return;

	mLen = (inLen != -1) ? inLen : vu_strlen( inUStr );

	int32_t NewLen	  = 0;
	int32_t SrcLen	  = mLen;
	int32_t TargetLen = SrcLen * mMaxCharSize;

	try
	{
		// Set buffer pointer.
		mAStr = (TargetLen + 1) > LOCAL_LEN ? new char[TargetLen + 1 * mMaxCharSize] : mLocal;
		UErrorCode Error = U_ZERO_ERROR;

		// Try in the loop to convert the string.
		while( 1 )
		{
			NewLen = mConverter->fromUChars( mAStr, TargetLen + 1 * mMaxCharSize, 
										inUStr, SrcLen, &Error );
			if( U_SUCCESS(Error) )
			{
				mLen = NewLen;
				break;
			}
			else
			{
				if( Error == U_BUFFER_OVERFLOW_ERROR )
				{
					// Not enought buffer size, correct it.
					if( mAStr != mLocal )
					{
						delete [] mAStr;
						mAStr = NULL;
					}
					
					mAStr = NewLen > LOCAL_LEN ? new char[NewLen + 1 * mMaxCharSize] : mLocal;
					
					TargetLen = NewLen;
					Error = U_ZERO_ERROR;
				}
				else
				{
					// FIXME: provide correct error code.
					FBL_Throw( xInternalError() );
				}
			}
		}
	}
	catch(...)
	{
		if( mAStr != mLocal )
		{
			delete [] mAStr;
			mAStr = NULL;
		}
		
		throw;
	}

	mAStr[mLen] = '\0';
}


/**********************************************************************************************/
void StFromUTF16::Free( void ) throw()
{
	if( mAStr != mLocal )
	{
	 	delete [] mAStr;
		mAStr = NULL;
		mLen = 0;
	}
}


#pragma mark -
#pragma mark ====== StToUTF16 ======= 


/**********************************************************************************************/
StToUTF16::StToUTF16( 
	ulong 			inToAllocate,
	const char* 	inEncoding )
:
	ConverterBase( inEncoding )
{
	fixme_argused1(inToAllocate); //???
	Init();
}


/**********************************************************************************************/
StToUTF16::StToUTF16( 
	const char* 	inAStr, 
	tslen 			inLen,
	const char* 	inEncoding )
:
	ConverterBase( inEncoding )
{
	Init();
	ConvertUsingInternalBuffer( inAStr, inLen );
}


#pragma mark -


/**********************************************************************************************/
StToUTF16::StToUTF16( 
	ulong 			inToAllocate,
	I_Converter* 	inConverter )
:
	ConverterBase( inConverter )
{
	fixme_argused1(inToAllocate); //???
	Init();
}


/**********************************************************************************************/
StToUTF16::StToUTF16( 
	const char* 	inAStr, 
	tslen 			inLen,
	I_Converter* 	inConverter )
:
	ConverterBase( inConverter )
{
	Init();
	ConvertUsingInternalBuffer( inAStr, inLen );
}


#pragma mark -


/**********************************************************************************************/
StToUTF16::~StToUTF16( void ) throw()
{
	Free();
}


/**********************************************************************************************/
void StToUTF16::Init( void ) throw()
{
	mUStr = 0;
	mLocal[ mLen = 0 ] = 0;
}


#pragma mark -


/**********************************************************************************************/
void StToUTF16::Convert( const char* inAStr, tslen inLen )
{
	Free();
	ConvertUsingInternalBuffer(inAStr, inLen);
}


#pragma mark -


/**********************************************************************************************/
void StToUTF16::ConvertUsingInternalBuffer( const char* inAStr, tslen inLen )
{
	if( !inAStr )
		return;

	tslen SrcLen = (inLen != - 1 ) ? inLen : tslen( strlen(inAStr) );

	UErrorCode Status	= U_ZERO_ERROR;

	int32_t	NewLen		= 0;
	int32_t	TargetLen	= SrcLen;

	// Set buffer pointer.
	mUStr = (TargetLen + 1) > LOCAL_LEN ? new UChar[TargetLen + 1] : mLocal;
	
	// Try in the loop to convert the string.
	try
	{
		while( 1 )
		{
			NewLen = mConverter->toUChars(mUStr, TargetLen + 1, inAStr, SrcLen, &Status);
			
			if( U_SUCCESS(Status) )
			{
				mLen = NewLen;
				break;
			}
			else
			{
				if( Status == U_BUFFER_OVERFLOW_ERROR )
				{
					// Not enought buffer size, correct it.
					if( mUStr != mLocal )
					{
						delete [] mUStr;
						mUStr = NULL;
					}
					
					mUStr = (NewLen + 1) > LOCAL_LEN ? new UChar[NewLen + 1] : mLocal;
					
					TargetLen = NewLen;
					Status = U_ZERO_ERROR;
				}
				else
				{
					// FIXME: provide correct error code.
					FBL_Throw( xInternalError() );
				}
			}
		}
	}
	catch(...)
	{
		if( mUStr != mLocal )
		{
			delete [] mUStr;
			mUStr = 0;
		}

		throw;
	}
}


/**********************************************************************************************/
void StToUTF16::Free( void ) throw()
{
	if( mUStr != mLocal )
	{
	 	delete [] mUStr;
		mUStr = NULL;
		mLen = 0;
	}
}


/**********************************************************************************************/
FBL_End_Namespace
